package com.oocl.im.clinet;

import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.oocl.im.gui.DynamicGui;
import com.oocl.im.pojo.MsgPackage;
import com.oocl.im.pojo.Operation;
import com.oocl.im.util.JsonUtil;

public class ClientImpl implements Client {
	private String sender;
	private String receiver;
	private Map<String, StringBuilder> chatHistoryMap;
	private Map<String, Boolean> hasLoginMap;
	private DynamicGui gui;

	private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
	Socket socket;
	BufferedReader reader;
	PrintStream writer;

	public ClientImpl(String sender, DynamicGui gui, Socket socket)
			throws Exception {
		this.sender = sender;
		this.gui = gui;
		this.socket = socket;
		this.chatHistoryMap = new HashMap<String, StringBuilder>();
		this.writer = new PrintStream(socket.getOutputStream());
		this.reader = new BufferedReader(new InputStreamReader(
				socket.getInputStream()));
		setReceiver("all");
		new Thread(new Receiver()).start();
	}

	@Override
	public void setReceiver(String receiver) {
		this.receiver = receiver;
		StringBuilder chatHistory = getChatHistory(receiver);
		gui.titleUpdate(sender, receiver);
		gui.chatUpdate(chatHistory.toString());
	}

	public StringBuilder getChatHistory(String receiver) {
		StringBuilder chatHistory = null;
		if (chatHistoryMap.containsKey(receiver)) {
			chatHistory = chatHistoryMap.get(receiver);
		} else {
			chatHistory = new StringBuilder();
			chatHistoryMap.put(receiver, chatHistory);
		}
		return chatHistory;
	}

	@Override
	public void chat(String content) {
		Date date = new Date();
		MsgPackage msg = new MsgPackage(Operation.CHAT, sender, receiver,
				content, date, null);
		String jsoString = JsonUtil.objectToString(msg);
		writer.println(jsoString);
		StringBuilder chatHistory = getChatHistory(receiver);
		chatHistory.append(sender + "\t" + sdf.format(msg.getDate()) + "\n"
				+ content + "\n");
		gui.chatUpdate(chatHistory.toString());
	}

	@Override
	public void shake() {
		if ("all".equals(receiver)) {
			StringBuilder chatHistory = getChatHistory("all");
			chatHistory.append("System hint: Can't shake all !!\n");
			gui.chatUpdate(chatHistory.toString());
		} else {
			MsgPackage msg = new MsgPackage(Operation.SHAKE, sender, receiver,
					null, new Date(), null);
			String jsoString = JsonUtil.objectToString(msg);
			writer.println(jsoString);
		}
	}

	@Override
	public void exit() {
		MsgPackage msg = new MsgPackage(Operation.EXIT, sender, null, null,
				new Date(), null);
		String jsoString = JsonUtil.objectToString(msg);
		try {
			writer.println(jsoString);
			socket.close();
		} catch (IOException e) {
			// e.printStackTrace();
		}
	}

	private class Receiver implements Runnable {
		public void run() {
			try {
				while (true) {
					String string = reader.readLine();
					MsgPackage msg = JsonUtil.stringToObject(string);
					System.out.println(msg);
					switch (msg.getOpeartion()) {
					case NOTIFY:
						notifyGui(msg);
						break;
					case CHAT:
						chatGui(msg);
						break;
					case SHAKE:
						shakeGui(msg);
						break;
					case EXIT:
						exitGui(msg);
						return;
					default:
						break;
					}
				}
			} catch (EOFException | SocketException | NullPointerException e) {
				System.out.println("socket has closed");
				exitGui("                    Disconnect !!");
			}

			catch (Exception e) {
				e.printStackTrace();
			}
		}

		public void notifyGui(MsgPackage msg) {
			hasLoginMap = msg.getOnlineMap();
			gui.friendListUpdate(hasLoginMap);
		}

		public void shakeGui(MsgPackage msg) {
			String sender = msg.getSender();
			setReceiver(sender);
			gui.shake();
		}

		public void chatGui(MsgPackage msg) {
			String receiver = "all".equals(msg.getReceiver()) ? "all" : msg
					.getSender();
			StringBuilder chatHistory = getChatHistory(receiver);
			chatHistory.append(msg.getSender() + "\t"
					+ sdf.format(msg.getDate()) + "\n" + msg.getContent()
					+ "\n");
			setReceiver(receiver);
		}

		public void exitGui(MsgPackage msg) {
			String exitMessage = msg.getContent();
			gui.exit(exitMessage);
		}

		public void exitGui(String msg) {
			gui.exit(msg);
		}
	}
}
